using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Text;
using System.Windows.Forms;

namespace org.synthful.Drawing
{

    /// <summary>
    /// Offered under Apache Public Licence 2.0
    /// synthful.org
    /// blessedgeek [@] synthful.org
    /// 
    /// Various classes for painting within bounds of shapes.
    /// ShapePainter is the base abstract class.
    /// </summary>
    abstract public class ShapePainter
    {
        virtual public void fillBounds(
           System.Windows.Forms.PaintEventArgs e,
           GraphicsPath path,
           RectangleF gradientBounds,
           Color color1, Color color2
           )
        {
            LinearGradientBrush bgBrush =
                new LinearGradientBrush(
                    gradientBounds, color1, color2,
                    this.GradientMode);

            using (bgBrush)
            {
                drawPath(path);
                bgBrush.WrapMode = WrapMode.TileFlipXY;
                e.Graphics.FillPath(bgBrush, path);
            }
        }

        virtual public void fillBounds(
           System.Windows.Forms.PaintEventArgs e,
           GraphicsPath path, Color color
           )
        {
            System.Drawing.Pen bgpen = new Pen(color);

            using (bgpen.Brush)
            {
                drawPath(path);
                e.Graphics.FillPath(bgpen.Brush, path);
            }
        }

        virtual public void drawBorder(
            System.Windows.Forms.PaintEventArgs e,
            GraphicsPath path,
            Color penColor)
        {
            using (Pen borderPen = DrawingUtils.getBorderPen(penColor))
            {
                drawPath(path);
                path.CloseFigure();
                e.Graphics.DrawPath(borderPen, path);
            }
        }
        public LinearGradientMode GradientMode = LinearGradientMode.Vertical;
        abstract protected void drawPath(GraphicsPath path);

    }

    public class Polygon : ShapePainter
    {
        public Polygon() { }

        public Polygon(PointF[] points)
        {
            Points = points;
        }

        override protected void drawPath(GraphicsPath path)
        {
            path.AddPolygon(Points);
        }

        public PointF[] Points;

        virtual public void TranslateGraphics(Graphics g, Rectangle r)
        {
            g.TranslateTransform(r.Width / 2, r.Height / 2);
        }

        public void draw(PaintEventArgs e, Rectangle r, DrawDirection d, Color c)
        {
            this.TranslateGraphics(e.Graphics, r);
            if (d != Polygon.DrawDirection.Down)
                e.Graphics.RotateTransform((float)d);
            GraphicsPath path = new GraphicsPath();
            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

            //this.drawBorder(e, path, this.ForeColor);
            this.fillBounds(e, path, c);
        }

        public enum DrawDirection
        {
            Down = 0,
            DownLeft = 45,
            Left = 90,
            UpLeft = 135,
            Up = 180,
            UpRight = 225,
            Right = 270,
            DownRight = 316,
        }
    }

    public class Triangle : Polygon
    {
        public Triangle(PointF p0, PointF p1, PointF p2)
            : base(new PointF[] { p0, p1, p2 })
        {}

        public Triangle(float size)
        {
            this.Points =
                new PointF[]{
                    new PointF(0f, size * 0.66f),
                    new PointF(size * 0.5f, -size * 0.33f),
                    new PointF(-size * 0.5f, -size * 0.33f)
                };
        }
    }

    public class RoundedRectangle : ShapePainter
    {
        public RoundedRectangle()
        {
        }

        public RoundedRectangle(
            int x, int y, int width, int height,
            float topLeftRadius,
            float topRightRadius,
            float bottomLeftRadius,
            float bottomRightRadius
            )
        {
            this.Bounds = new Rectangle(x, y, width, height);
            TopLeftRadius = topLeftRadius;
            TopRightRadius = topRightRadius;
            BottomLeftRadius = bottomLeftRadius;
            BottomRightRadius = bottomRightRadius;
        }

        public RoundedRectangle(
            Rectangle r,
            float topLeftRadius,
            float topRightRadius,
            float bottomLeftRadius,
            float bottomRightRadius
            )
        {
            this.Bounds = r;
            TopLeftRadius = topLeftRadius;
            TopRightRadius = topRightRadius;
            BottomLeftRadius = bottomLeftRadius;
            BottomRightRadius = bottomRightRadius;
        }

        public RoundedRectangle(Rectangle r) : this(r, 0) { }

        public RoundedRectangle(Rectangle r, float cornerRadii)
        {
            this.Bounds = r;
            TopLeftRadius =
            TopRightRadius =
            BottomLeftRadius =
            BottomRightRadius = cornerRadii;
        }

        override protected void drawPath(GraphicsPath path)
        {
            path.AddArc(
                this.Bounds.Right, this.Bounds.Bottom,
                this.BottomRightRadius, this.BottomRightRadius,
                0, 90);
            path.AddArc(
                this.Bounds.Left, this.Bounds.Bottom,
                this.BottomLeftRadius, this.BottomLeftRadius,
                90, 90);
            path.AddArc(
                this.Bounds.Left, this.Bounds.Top,
                this.TopLeftRadius, this.TopLeftRadius,
                180, 90);
            path.AddArc(
                this.Bounds.Right, this.Bounds.Top,
                this.TopRightRadius, this.TopRightRadius,
                270, 90);
        }

        public Rectangle Bounds;

        public float
            TopLeftRadius,
            TopRightRadius,
            BottomLeftRadius,
            BottomRightRadius
            ;
    }

    public class ShapePainterBounds
    {
        public RectangleF GradientBounds;
        public ShapePainter Painter;
    }

}

